import CryptoJS from '../miniprogram_npm/crypto-js/index'
import WxmpRsa from '../miniprogram_npm/wxmp-rsa/index'
import Toast from '../miniprogram_npm/@vant/weapp/toast/toast';


/*随机字符窜*/
const dict = "!#$%&'()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
const randomStr = length => {
  let res = '';
  for (let i = 0; i < length; i++) {
    let index = Math.abs(Math.floor(Math.random() * dict.length - 1));
    res = res + dict[index];
  }
  return res;
}


const SysConstParams = {
  debug: false,
  appName: "/miay",
  server: "https://itwater.imwork.net:32210",//后台服务地址
  aesKey: randomStr(16),
  rsaPublicKey: `
  -----BEGIN PUBLIC KEY-----
  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoUuGZQjg2GZlLCMgMVFB
  XBOJg64UuMEKBgzvqLU7MGdVKK1lOXzCWCvjOQvxrGZuVy4p50Z0ox4ipK0Nibz8
  LfA6n4kSeljEuNqfi9LNJ5SPEefEviH3tmSSCbAuVh1/IiDPFchs/U7oJuMSl7qy
  hBGdxeFL0BAeuI5CriK1+lXULisIsAuo75J+YYEBixLmpBRLs05DDd0dGSUO7mNI
  hW2cycSGJo0+C102V4ky23g76g/PIQYH/OBFdBF0obor7Wt7w6scPOTcv/eMV6pn
  2yYtss7kx8MHMxoEYNCxZFgHtahgKLZRHGbN1R2zdvgL6MgWDgEo7nOcH+521rie
  WQIDAQAB
  -----END PUBLIC KEY-----
  `,//密钥交换采用的公钥信息，后台存储私钥
  sessionKey: ""//会话密钥
}

/*rsa*/
const rsa = new WxmpRsa()
rsa.setPublicKey(SysConstParams.rsaPublicKey)
const rsaEncrypt = sourceStr => {
  return rsa.encryptLong(sourceStr);
}


/*aes*/
const aesEncrypt = (source) => {
  let key = CryptoJS.enc.Utf8.parse(SysConstParams.aesKey);
  let res = CryptoJS.AES.encrypt(source, key, {
    iv: key,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  }).ciphertext.toString(CryptoJS.enc.Base64);
  return res;
}

const aesDecrypt = source => {
  let key = CryptoJS.enc.Utf8.parse(SysConstParams.aesKey);
  return CryptoJS.AES.decrypt(source, key, {
    iv: key,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  }).toString(CryptoJS.enc.Utf8);
}

/*base64*/
const strToBase64 = str => {
  let res = '';
  let wordArray = CryptoJS.enc.Utf8.parse(str);
  res = CryptoJS.enc.Base64.stringify(wordArray);
  return res;
}
const base64ToStr = base64Str => {
  let res = '';
  let parsedWordArray = CryptoJS.enc.Base64.parse(base64Str);
  res = parsedWordArray.toString(CryptoJS.enc.Utf8);
  return res;
}

/*sha256*/
const sha256 = str => {
  return CryptoJS.SHA256(str).toString(CryptoJS.enc.Hex);
}

/*日期格式化*/
const formatTime = date => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()

  return `${[year, month, day].map(formatNumber).join('-')} ${[hour, minute, second].map(formatNumber).join(':')}`
}

const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : `0${n}`
}

const createRequestUrl = service => {
  return SysConstParams.server + SysConstParams.appName + "/" + service;
}

/**
 * 完成与后台服务握手，交换会话密钥，生成会话标识
 * @param {string} hello 握手信息，采用wx.login获取的loginCode
 * @param {function} successFun 握手信息交换成功调用的方法
 * @param {function} failFun 握手失败调用的方法
 */
const secureInit = (hello, successFun, failFun) => {
  wx.request({
    url: createRequestUrl("open/common/sec/init-1.0.0"),
    method: "POST",
    data: {
      "client_hello": aesEncrypt(hello + "|" + sha256(hello + SysConstParams.aesKey)),
      "secret": rsaEncrypt(SysConstParams.aesKey)
    },
    success: successFun,
    fail: failFun
  })
}

/**
 * 安全的http服务，交易报文采用加密方式
 * @param service 服务名称
 * @param data 请求数据
 * @param method 请求方法
 * @param processSuccessFun 业务成功方法
 * @param requestError 通讯级错误  
 * @param processFailFun 业务错误方法
 * 
*/
const secureHttp = (service, data = {}, method = "POST", processSuccessFun, requestError, processFailFun) => {
  let timeStamp = formatTime(new Date());
  data["_re_id"] = randomStr(20);
  let jsonData = JSON.stringify(data);
  let reqMac = sha256(SysConstParams.sessionKey + jsonData + timeStamp)
  let secureData = {
    "s_session_key": SysConstParams.sessionKey,
    "s_time_stamp": timeStamp,
    "s_data": aesEncrypt(jsonData),
    "s_mac": reqMac
  };
  wx.request({
    url: createRequestUrl(service),
    method: method,
    data: secureData,
    success: function (res) {
      //数据解密
      if (res.data["header"]["status_code"] == "000000") {
        let s_respData = aesDecrypt(res.data["body"]["s_resp"])
        processSuccessFun(JSON.parse(s_respData));
      } else {
        if (processFailFun != undefined) {
          processFailFun(res.data["header"])
        } else {
          requestError(res);
        }
      }
    },
    fail: requestError
  })
}

/**
 * 校验会话是否有效，无效重新登录，交换会话密钥
 * @param {App} app 
 * @param {string} toastId 
 */
const checkSession = (app, toastId) => {
  //会话验证
  secureHttp("secure/common/session/valid-1.0.0", { "valid": "ok" }, "POST", function (res) {
    app.globalData.NETWORK_OK = true;
    app.globalData.SESSION_OK = true;
  }, function (res) {
    app.globalData.NETWORK_OK = false;
    let toastParam = { type: 'fail', message: '网络异常', duration: 3000 };
    if (toastId != undefined) {
      toastParam.selector = toastId;
    }
    Toast(toastParam);
  }, function (res) {
    app.globalData.SESSION_OK = false;
    let toastParam = { type: 'fail', message: '会话失效，重新登录中...', duration: 0 };
    if (toastId != undefined) {
      toastParam.selector = toastId;
    }
    let toast = Toast(toastParam);
    // 登录
    wx.login({
      success: res => {
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
        secureInit(res.code, function (res) {
          app.globalData.NETWORK_OK = true;
          if (res.data["header"]["status_code"] == "000000") {
            app.globalData.HELLO_OK = true;
            let server_hi = aesDecrypt(res.data["body"]["server_hi"]);
            let session_key = server_hi.split("|")[0];
            let server_hi_mac = server_hi.split("|")[1];
            let local_session_hi_mac = sha256(session_key + SysConstParams.aesKey);
            if (local_session_hi_mac == server_hi_mac) {
              SysConstParams.sessionKey = session_key;
              app.globalData.NETWORK_SECRET = true;
              toast.clear();
              if (SysConstParams.debug) {
                wx.setStorageSync("debug_session_key", session_key);
                wx.setStorageSync("debug_session_secret", SysConstParams.aesKey);
              }
            } else {
              console.log("网络环境不安全");
              app.globalData.NETWORK_SECRET = false;
              toast.setData({
                duration: 2,
                type: "fail",
                message: "网络不安全"
              });    
            }
          } else {
            app.globalData.HELLO_OK = false;
          }
        }, function () {
          console.log("网络异常");
          app.globalData.NETWORK_OK = false;
          toast.setData({
            duration: 2,
            type: "fail",
            message: "服务异常"
          });  
        }
        );
      }
    })
  })
}


module.exports = {
  SysConstParams,
  formatTime,
  strToBase64,
  base64ToStr,
  sha256,
  rsaEncrypt,
  aesEncrypt,
  aesDecrypt,
  randomStr,
  secureInit,
  secureHttp,
  checkSession
}
